package model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import model.dao.PrecoProdutoDAO;
import model.dao.ProdutoDAO;
import model.dao.VendaDAO;
import model.dao.VendedorDAO;

public class Loja {
    
    private HashMap<String, Produto> produtos;
    private HashMap<String, Vendedor> vendedores;
    private List<Venda> vendas;

    public Loja() {
        this.vendedores = new HashMap<>();
        this.produtos = new HashMap<>();
        this.vendas = new ArrayList<>();
    }

    public Loja(HashMap<String, Produto> produtos, HashMap<String, Vendedor> vendedores, List<Venda> vendas) {
        this.produtos = produtos;
        this.vendedores = vendedores;
        this.vendas = vendas;
    }
    
    /**
     * Função que importa os dados de produtos de um arquivo texto.
     * @param nomeArquivo - caminho para o arquivo texto.
     * @param leitor - leitor de texto do tipo {@link ProdutoDAO}.
     * @throws Exception Se ocorrer algum erro ao tentar encontrar o arquivo.
     */
    public void importarDadosProdutos(String nomeArquivo, ProdutoDAO leitor) throws Exception{
        List<Produto> produtosImportados = new ArrayList<Produto>();
        try{
            produtosImportados = leitor.importarDados(nomeArquivo);
        } catch (Exception e){
            throw new Exception(e.getMessage());
        }
        alterarEadicionarProdutos(produtosImportados);
    }
    
    /**
     * Função que adiciona os produtos importados e faz as alterações necessárias caso o produto já esteja registrado. 
     * @param produtosImportados - lista de produtos importados pelo arquivo texto.
     */
    private void alterarEadicionarProdutos(List<Produto> produtosImportados) {
        for (Produto p : produtosImportados) {
            Produto produto = this.produtos.get(p.getCodigo());     
            if (produto != null) 
                produto.setNome(p.getNome());
            else
                this.produtos.put(p.getCodigo(), p);
        }
    }
    
   /**
     * Função que importa os dados de preços de produtos de um arquivo texto.
     * @param nomeArquivo - caminho para o arquivo texto.
     * @param leitor - leitor de texto do tipo {@link PrecoProdutoDAO}.
     * @throws Exception Se ocorrer algum erro ao tentar encontrar o arquivo ou se o arquivo estiver fora do padrão.
    */
    public void importarPrecoProdutos(String nomeArquivo, PrecoProdutoDAO leitor) throws Exception{
        List<Produto> produtosComNovoPreco = new ArrayList<Produto>();
        try {
            produtosComNovoPreco = leitor.importarDados(nomeArquivo);
	} catch (Exception e) {
            throw new Exception("O arquivo texto está fora do padrão. Por favor observe o exemplo.");
	}

        alterarPrecoProdutos(produtosComNovoPreco);
    }

    /**
     * Função as alterações de preço caso o produto já esteja registrado e adiciona a data de vigencia do preço caso
     * esteja nula.
     * @param produtosComNovoPreco - lista de produtos a serem atualizados.
     */
    private void alterarPrecoProdutos(List<Produto> produtosComNovoPreco) {
        for (Produto p : produtosComNovoPreco) {
            Produto produto = this.produtos.get(p.getCodigo());
            if (produto != null) {
                if (produto.getDataVigenciaPreco() == null) {
                    produto.setDataVigenciaPreco(p.getDataVigenciaPreco());
                }
                produto.setPreco(p.getPreco());
            }
        }
    }
    
    /**
     * Função que importa os dados de vendas de um arquivo texto.
     * @param nomeArquivo - caminho para o arquivo texto.
     * @param leitor - leitor de texto do tipo {@link VendaDAO}.
     * @throws Exception Se ocorrer algum erro ao tentar encontrar o arquivo ou se o arquivo estiver fora do padrão.
     */
    public void importarVendas(String nomeArquivo, VendaDAO leitor) throws Exception{
        List<Venda> vendasImportadas = new ArrayList<Venda>();
        try{
            vendasImportadas = leitor.importarDados(nomeArquivo);
            this.vendas.addAll(vendasImportadas);
        } catch (Exception e){
            throw new Exception("O arquivo texto está fora do padrão. Por favor observe o exemplo.");
        }
    }

    /**
     * Função que importa os dados de vendedores de um arquivo texto.
     * @param nomeArquivo - caminho para o arquivo texto.
     * @param leitor - leitor de texto do tipo {@link VendedorDAO}.
     * @throws Exception Se ocorrer algum erro ao tentar encontrar o arquivo ou se o arquivo estiver fora do padrão.
     */
    public void importarVendedores(String nomeArquivo, VendedorDAO leitor) throws Exception{
        List<Vendedor> vendedoresImportados = new ArrayList<>();
        try{
            vendedoresImportados = leitor.importarDados(nomeArquivo);
        } catch (Exception e){
            throw new Exception("O arquivo texto está fora do padrão. Por favor observe o exemplo.\n"+e.getMessage());
        }
        alterarEadicionarVendedores(vendedoresImportados);
    }
    
    /**
     * Função que adiciona os vendedores importados e faz as alterações necessárias caso o vendedorS já esteja registrado. 
     * @param vendedoresImportados - lista de vendedors importados pelo arquivo texto.
     */
    private void alterarEadicionarVendedores(List<Vendedor> vendedoresImportados) {
        for (Vendedor v : vendedoresImportados) {
            Vendedor vendedor = this.vendedores.get(v.getCodigo());
            if (vendedor != null) {
                vendedor.setNome(v.getNome());
                vendedor.setCategoria(v.getCategoria());
            }else{
                this.vendedores.put(v.getCodigo(), v);
            }
        }
    }

    /**
     * Função que obtém os totais de vendas e de comissões dos vendedores cadastrados na loja durante um periodo de 
     * tempo determinado.
     * @param mesInicial - mês do inicio do período.
     * @param anoInicial - ano do inicio do período.
     * @param mesFinal - mês do fim do período.
     * @param anoFinal - ano do fim do período
     * @return Um hashmap contendo o vendedor como chave e uma string associada contendo os valores dos totais de 
     * vendas e de comissões, respectivamente, separados por ;
     */
    public HashMap<Vendedor, String> obterTotaisVendedores(int mesInicial, int anoInicial, int mesFinal, int anoFinal){
        HashMap<Vendedor, String> totalVendasVendedores = new HashMap<>();
        Collection<Vendedor> vendedoresDaLoja = this.vendedores.values();
        for(Vendedor vendedor : vendedoresDaLoja){
            List<Venda> vendasVendedor = vendedor.obterVendasVendedor(this.vendas, mesInicial, anoInicial, mesFinal, anoFinal);
            double totalVendas = obterTotalVendas(vendasVendedor, this.produtos);
            double comissao = Comissao.obterComissao(vendedor, totalVendas);
            String totais = Double.toString(totalVendas)+";"+Double.toString(comissao);
            totalVendasVendedores.put(vendedor, totais);
        }
        
        return totalVendasVendedores;
    }
    
    /**
     * Função que obtém os totais de vendas de uma lista qualquer, relacionada com um hashmap de produtos.
     * @param vendas - lista de vendas.
     * @param produtos - hashmap<String, Produto>. 
     * @return Um double com o valor total das vendas.
     */
    public double obterTotalVendas(List<Venda> vendas, HashMap<String, Produto> produtos){
        double total = 0;
        for(Venda venda : vendas){
            Produto produto = produtos.get(venda.getCodigoProduto());
            double precoProduto = produto.getPreco();
            total += venda.getQuantidadeVendidaProduto() * precoProduto;
        }
        return total;
    }
    
    /**
     * Função que obtém as médias das vendas e das comissões dos vendedores cadastrados na loja durante um periodo 
     * de tempo determinado.
     * @param mesInicial - mês do inicio do período.
     * @param anoInicial - ano do inicio do período.
     * @param mesFinal - mês do fim do período.
     * @param anoFinal - ano do fim do período
     * @return Um hashmap contendo o vendedor como chave e uma string associada contendo os valores das médias de 
     * vendas e de comissões, respectivamente, separadas por ;
     */
    public HashMap<Vendedor, String> obterMediasVendedores(int mesInicial, int anoInicial, int mesFinal, int anoFinal){
        HashMap<Vendedor, String> mediaVendasVendedores = new HashMap<>();
        Collection<Vendedor> vendedoresDaLoja = this.vendedores.values();
        for(Vendedor vendedor : vendedoresDaLoja){
            List<Venda> vendasVendedor = vendedor.obterVendasVendedor(vendas, mesInicial, anoInicial, mesFinal, anoFinal);
            double mediaVendas = obterTotalVendas(vendasVendedor, produtos)/vendasVendedor.size();
            double mediaComissao = Comissao.obterComissao(vendedor, mediaVendas)/vendasVendedor.size();
            String totais = Double.toString(mediaVendas)+";"+Double.toString(mediaComissao);
            mediaVendasVendedores.put(vendedor, totais);
        }
        
        return mediaVendasVendedores;
    }
    
    public List<Venda> getVendas() {
        return vendas;
    }

    public void setVendas(List<Venda> vendas) {
        this.vendas = vendas;
    }
    
    public HashMap<String, Produto> getProdutos() {
        return produtos;
    }

    public void setProdutos(HashMap<String, Produto> produtos) {
        this.produtos = produtos;
    }

    public HashMap<String, Vendedor> getVendedores() {
        return vendedores;
    }

    public void setVendedores(HashMap<String, Vendedor> vendedores) {
        this.vendedores = vendedores;
    }
    
}
